using System.Windows.Input;

namespace TheSalLab.MauiBehaviors;

public sealed class MauiInvokeCommandAction : BindableObject, IMauiAction {
    public static readonly BindableProperty CommandProperty =
        BindableProperty.Create(nameof(Command), typeof(ICommand),
            typeof(MauiInvokeCommandAction));

    public static readonly BindableProperty CommandParameterProperty =
        BindableProperty.Create(nameof(CommandParameter), typeof(object),
            typeof(MauiInvokeCommandAction));

    public static readonly BindableProperty InputConverterProperty =
        BindableProperty.Create(nameof(Converter), typeof(IValueConverter),
            typeof(MauiInvokeCommandAction));

    public static readonly BindableProperty InputConverterParameterProperty =
        BindableProperty.Create(nameof(ConverterParameter), typeof(object),
            typeof(MauiInvokeCommandAction));

    public ICommand Command {
        get => (ICommand)GetValue(CommandProperty);
        set => SetValue(CommandProperty, value);
    }

    public object CommandParameter {
        get => GetValue(CommandParameterProperty);
        set => SetValue(CommandParameterProperty, value);
    }

    public IValueConverter Converter {
        get => (IValueConverter)GetValue(InputConverterProperty);
        set => SetValue(InputConverterProperty, value);
    }

    public object ConverterParameter {
        get => GetValue(InputConverterParameterProperty);
        set => SetValue(InputConverterParameterProperty, value);
    }

    public async Task<bool> Execute(object sender, object parameter) {
        if (Command is null) {
            return false;
        }

        object resolvedParameter;
        if (CommandParameter is not null) {
            resolvedParameter = CommandParameter;
        } else if (Converter is not null) {
            resolvedParameter = Converter.Convert(parameter, typeof(object),
                ConverterParameter, null);
        } else {
            resolvedParameter = parameter;
        }

        if (!Command.CanExecute(resolvedParameter)) {
            return false;
        }

        Command.Execute(resolvedParameter);
        return true;
    }
}